`include "PRV564Config.v"
`include "PRV564Define.v"
//TODO BUS BROADCAST PROCESS
//TODO BUS WRITE PIPELINING
module FIB_BIU_L1D
#(parameter FIBID=8'h00,SEQ_CNT_WID=3)(
    // global input
    input GLBi_CLK,
    input GLBi_ARST,
    // master request
    output     BIUo_WREN,
    output [7:0] BIUo_ID,
    output reg BIUo_REQ,
    output reg [7:0] BIUo_CMD,
    output reg [3:0] BIUo_BURST,
    output reg [3:0] BIUo_SIZE,
    output reg [`PADR-1:0] BIUo_ADDR,
    output [`XLEN-1:0] BIUo_DATA,
    // slave reply
    input BIUi_FULL,
    input BIUi_ACK,
    input BIUi_V,
    input[7:0] BIUi_ID,
    input[7:0] BIUi_RPL,
    input[`XLEN-1:0] BIUi_DATA,
    //Cache Controller Interface

    input single_write_req,	//请求写穿
    input seq_write_req,	//请求写穿
    input single_read_req,	//请求读一次
    input seq_read_req,		//请求读一行
    input amo_req,
    input [7:0]amo_cmd,
    input [3:0]seq_size,//包请求尺寸
    input [3:0]req_bsel,    
    input [`PADR-1:0]bus_addr,		
    input [63:0]bus_wdata,
    output [63:0]bus_rdata,
    output [SEQ_CNT_WID-1:0]addr_count,//no value
    output data_valid,			//cache写
    output reg trans_error,
    output bus_trans_finish			//传输完成
);
    localparam IDLE = 3'h0;//nothing happening 
    localparam CMDO = 3'h1;//Command Out
    localparam PNDR = 3'h2;//Data pending read
    localparam PNDW = 3'h3;//data pending write
    localparam RETW = 3'h4;//Write wait for handshake
    localparam WAIT = 3'h5;//Wait for handshake complete(request withdraw)
    reg [2:0]state;
    reg [SEQ_CNT_WID-1:0]datacnt;
    reg [2:0]state_next;
    reg [7:0]cmd_decode;

    wire recv_valid,tran_valid,broadcast_valid;
    wire bw_wen;
    wire [SEQ_CNT_WID-1:0]datcnt_valcmp;
    assign datcnt_valcmp=(({{SEQ_CNT_WID-2{1'h0}},1'b1} << BIUo_BURST)-1);
    assign recv_valid=(FIBID == BIUi_ID) & BIUi_V;
    assign broadcast_valid = (FIBID == 8'h00) & BIUi_V;//broadcast signal
    assign tran_valid=BIUi_ACK & !(BIUi_FULL);
    assign BIUo_ID=FIBID;
    assign data_valid= (state==PNDR) & (recv_valid & (BIUi_RPL==`FIB_RPL_TRDY | BIUi_RPL==`FIB_RPL_SEQ));
    assign BIUo_DATA = bus_wdata;
    assign bus_rdata= BIUi_DATA;
    assign bus_trans_finish=(state_next==WAIT);

    assign addr_count=datacnt;//+{2'b0,seq_write_req}
    always@(*)
    begin
        casez({amo_req,single_write_req,seq_write_req,single_read_req,seq_read_req})
            5'b1????:cmd_decode=amo_cmd;
            5'b01000:cmd_decode=`FIB_CMD_SIGW;
            5'b00100:cmd_decode=`FIB_CMD_SEQW;
            5'b00010:cmd_decode=`FIB_CMD_SIGR;
            5'b00001:cmd_decode=`FIB_CMD_SEQR;
            5'b00000:cmd_decode=`FIB_CMD_NOOP;
            default: cmd_decode=`FIB_CMD_NOOP;
        endcase
    end
//REQo
always @(posedge GLBi_CLK or posedge GLBi_ARST) 
begin
    if (GLBi_ARST) 
        BIUo_REQ<=1'b0;
    else 
    case(state_next)
        IDLE:
            BIUo_REQ<=1'b0;
        CMDO:
            BIUo_REQ<=1'b1;
        PNDR:
            BIUo_REQ<=1'b0;
        PNDW:
            BIUo_REQ<=1'b1;
        RETW:
            BIUo_REQ<=1'b0;
        WAIT:
            BIUo_REQ<=1'b0;
        default:
            BIUo_REQ<=1'b0;
    endcase
end
assign BIUo_WREN=BIUo_REQ;
//datacnt
always @(posedge GLBi_CLK or posedge GLBi_ARST) 
begin
    if (GLBi_ARST) 
        datacnt<=0;
    else 
    case(state_next)
        IDLE:
            datacnt<=0;
        CMDO:
            datacnt<=0;
        PNDR:
            datacnt<=datacnt+
                {{SEQ_CNT_WID-2{1'h0}},(recv_valid & (BIUi_RPL==`FIB_RPL_TRDY | BIUi_RPL==`FIB_RPL_SEQ))};
        PNDW:
            datacnt<=datacnt+{{SEQ_CNT_WID-2{1'h0}},tran_valid};
        RETW:
            datacnt<=0;
        WAIT:
            datacnt<=0;
        default:
            datacnt<=0;
    endcase
end
//Bus Signal Group
always @(posedge GLBi_CLK) 
case(state_next)
    IDLE:
    begin
        BIUo_CMD<=cmd_decode;
        BIUo_BURST<=seq_size;
        BIUo_SIZE<=req_bsel;//
        BIUo_ADDR<=bus_addr;
    end
    CMDO:
    begin
        BIUo_CMD<=cmd_decode;
        BIUo_BURST<=seq_size;
        BIUo_SIZE<=req_bsel;//
        BIUo_ADDR<=bus_addr;
    end
    PNDR:
    begin
        BIUo_CMD<=BIUo_CMD;
        BIUo_BURST<=BIUo_BURST;
        BIUo_SIZE<=BIUo_SIZE;//
        BIUo_ADDR<=BIUo_ADDR;
    end
    PNDW:
    begin
        BIUo_BURST<=BIUo_BURST;
        BIUo_SIZE<=BIUo_SIZE;//
        BIUo_ADDR<=BIUo_ADDR;
        if(datacnt == (datcnt_valcmp - 1))BIUo_CMD<=`FIB_CMD_SEQE;
        else BIUo_CMD<=BIUo_CMD;
    end
    default:
    begin
        BIUo_CMD<=0;
        BIUo_BURST<=0;
        BIUo_SIZE<=0;//
        BIUo_ADDR<=0;
    end
endcase

// finite state Machine
always@(*)
begin
    trans_error=1'b0;
    case(state)
        IDLE:
            if(cmd_decode!=`FIB_CMD_NOOP) 
                state_next=CMDO;
            else 
                state_next=IDLE;
        CMDO:
            if(BIUi_FULL | !BIUi_ACK)
                state_next=CMDO;
            else if(single_write_req)
                state_next=RETW;//
            else if(seq_write_req)
                state_next=PNDW;
            else state_next=PNDR;
        PNDR:
            if(recv_valid & BIUi_RPL==`FIB_RPL_IDLE)
                state_next=CMDO;
            else if((recv_valid & (BIUi_RPL==`FIB_RPL_TRDY | BIUi_RPL==`FIB_RPL_TERR)) & 
                    (datacnt >= datcnt_valcmp))
                    begin
                        state_next=WAIT;
                        if( BIUi_RPL==`FIB_RPL_TERR)trans_error=1'b1;
                    end
            else state_next=PNDR; 
        PNDW:
            if(datacnt == datcnt_valcmp)
                state_next=RETW;
            else state_next=PNDW;    
        RETW:
            if(recv_valid & BIUi_RPL==`FIB_RPL_IDLE )
                begin
                    state_next=CMDO;
                    trans_error=1'b1;
                end
            else if(recv_valid & (BIUi_RPL==`FIB_RPL_TRDY| BIUi_RPL==`FIB_RPL_TERR))
                begin
                    state_next=WAIT;
                    if( BIUi_RPL==`FIB_RPL_TERR)trans_error=1'b1;
                end
            else 
                state_next=RETW; 
        WAIT:
            if(single_write_req | seq_write_req | single_read_req | seq_read_req)
                state_next=WAIT;
            else 
                state_next=IDLE;
        default: 
            state_next=IDLE;
    endcase
end

always @(posedge GLBi_CLK or posedge GLBi_ARST) 
begin
    if (GLBi_ARST)
        state <= IDLE;
    else
        state <= state_next;
end

endmodule
